/*
 * Restriction.java
 *
 * Created on 19 marzo 2004, 15.39
 */

package net.ermannofranco.xml.schema;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Restriction types and inner classes.
 * 
 * @author ermanno (ermanno.franco@gmail.com)
 */
public class RestrictionSimpleType extends SchemaTag implements
		BaseTypeContainer {

	private static final long serialVersionUID = 4296247673822734397L;
	private List<XmlType> baseTypes = null;

	private boolean typeAssigned;
	private final Map<String, Boolean> occurrences = new HashMap<String, Boolean>();
	private SimpleType simpleType;

	/**
	 * Creates a new instance of Restriction Protetto
	 * 
	 * @param level
	 *            livello di indentazione
	 * @param container
	 *            tag contenitore
	 */
	protected RestrictionSimpleType(int level, SchemaTag container) {
		super("restriction", level, container);
	}

	/**
	 * @param simpleTypeNumber
	 * @return
	 */
	protected RestrictionSimpleType setBase(XmlType simpleTypeNumber) {
		if (typeAssigned)
			throw new SchemaException("Type already assigned");
		addAttr("base", getLocalNS() + ":" + XmlType.getType(simpleTypeNumber));
		if (baseTypes == null)
			baseTypes = new ArrayList<XmlType>();
		baseTypes.add(simpleTypeNumber);
		typeAssigned = true;
		return this;
	}

	protected RestrictionSimpleType setBase(SimpleType simpleType) {
		if (typeAssigned)
			throw new SchemaException("Type already assigned");
		addAttr("base", feedFormPrefix(simpleType.getTypeName()));
		if (baseTypes == null)
			baseTypes = new ArrayList<XmlType>();
		baseTypes.addAll(simpleType.getBaseTypes());
		typeAssigned = true;
		return this;
	}

	public RestrictionSimpleType addEnumerationFacet(String... values) {
		if (!typeAssigned)
			throw new SchemaException(
					"Must assign base or simpleType before adding facets...");
		if (values == null) {
			log.warn("values null!!!");
			return this;
		}
		for (int i = 0; i < values.length; i++) {
			IFacet facet = new Facet.Enumeration(getLevel() + 1, this,
					getBaseTypes().toArray(new XmlType[0]));
			facet.setValue(values[i]);
			add(facet);
		}
		return this;

	}

	/**
	 * @param facetType
	 * @param value
	 * @return
	 */
	public RestrictionSimpleType addFacet(Facet facetType, String value) {
		if (!typeAssigned)
			throw new SchemaException(
					"Must assign base or simpleType before adding facets...");
		String key = getKey(facetType);
		if (key != null) {
			Boolean already = occurrences.get(key);
			if (Boolean.TRUE.equals(already)) {
				throw new SchemaException(facetType + " already assigned");
			}
		}
		IFacet facet;
		(facet = Facet.getFacet(facetType, getLevel(), this, getBaseTypes()
				.toArray(new XmlType[0]))).setValue(value);
		add(facet);
		if (key != null) {
			occurrences.put(key, Boolean.TRUE);
		}
		return this;
	}

	/**
	 * @return
	 */
	public Attribute addTagAttribute() {
		Attribute att;
		add(att = new Attribute(getLevel() + 1, this));
		return att;
	}

	/**
	 * @return
	 */
	public SimpleType setSimpleType() {
		if (typeAssigned)
			throw new SchemaException("Type already assigned");
		SimpleType t;
		add(t = new SimpleType(getLevel() + 1, this));
		simpleType = t;
		typeAssigned = true;
		return t;
	}

	// /**
	// * @param name
	// * @return
	// */
	// public SimpleType setSimpleType(String name) {
	// return setSimpleType().setName(name);
	// }

	/**
	 * aggiunge un tag Annotation che contiene un tag Documentation
	 * 
	 * @param explanation
	 *            Stringa di documentazione
	 * @return autoriferimento all'oggetto corrente
	 */
	public RestrictionSimpleType addDocumentation(String explanation) {
		addAnnotation().addDocumentation(explanation);
		return this;
	}

	/**
	 * @param explanation
	 * @param language
	 * @return
	 */
	public RestrictionSimpleType addDocumentation(String explanation,
			String language) {
		addAnnotation().addDocumentation(explanation, language);
		return this;
	}

	private static String getKey(Facet f) {
		switch (f) {
		case FRACTIONDIGITS:
			return "fractionD";

		case TOTALDIGITS:
			return "totalD";

		case MAXEXCLUSIVE:
		case MAXINCLUSIVE:
			return "maxBounded";

		case MINEXCLUSIVE:
		case MININCLUSIVE:
			return "minBounded";

		case LENGTH:
			return "lengt";

		case MINLENGTH:
			return "minLengt";

		case MAXLENGTH:
			return "maxLengt";

		default:
			return null;
		}
	}

	public List<XmlType> getBaseTypes() {
		if (baseTypes == null)
			return simpleType.getBaseTypes();
		else
			return baseTypes;
	}

}
